package com.suny.sf_server.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.suny.AccountInfo.dto.AccountInfoAddDTO;
import com.suny.AccountInfo.dto.AccountInfoPutDTO;
import com.suny.AccountInfo.vo.AccountVO;
import com.suny.constant.RedisKeyConstant;
import com.suny.result.ResponseCode;
import com.suny.sf_server.mapper.AccountInfoMapper;
import com.suny.sf_server.service.AccountInfoService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.suny.AccountInfo.domain.AccountInfo;
import com.suny.AccountInfo.dto.LoginDTO;
import com.suny.AccountInfo.vo.AccountInfoVO;
import com.suny.exception.BusinessException;
import com.suny.result.PageDTO;
import com.suny.sf_server.redis.IRedisService;
import lombok.extern.slf4j.Slf4j;
import com.suny.AccountInfo.dto.AccountQueryDTO;

import java.util.Date;
import java.util.Objects;

/**
 * @author sun
 * @description 针对表【account_info(人员管理表)】的数据库操作Service实现
 * @createDate 2024-12-26 13:58:42
 */
@Service
@Slf4j
public class AccountInfoServiceImpl extends ServiceImpl<AccountInfoMapper, AccountInfo>
        implements AccountInfoService {

    @Resource
    private AccountInfoMapper accountInfoMapper;

    @Resource
    private IRedisService redisService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(AccountInfoPutDTO accountInfoPutDTO) {
        //手机号参数校验以及必须是数字
        if (accountInfoPutDTO.getAccPhone() == null || accountInfoPutDTO.getAccPhone().length() != 11 || !accountInfoPutDTO.getAccPhone().matches("\\d+")) {
            throw new BusinessException(ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        // 获取原有用户信息
        LambdaQueryWrapper<AccountInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AccountInfo::getAccount, accountInfoPutDTO.getAccount());
        AccountInfo oldAccountInfo = getOne(wrapper);
        if (oldAccountInfo == null) {
            throw new BusinessException("用户不存在");
        }

        String oldPhone = oldAccountInfo.getAccPhone();
        
        // 如果传入了手机号且与原手机号不同，才进行手机号唯一性检查
        if (accountInfoPutDTO.getAccPhone() != null && !accountInfoPutDTO.getAccPhone().equals(oldPhone)) {
            checkPhoneExists(accountInfoPutDTO.getAccPhone(), accountInfoPutDTO.getAccount());
            oldAccountInfo.setAccPhone(accountInfoPutDTO.getAccPhone());
        }

        // 如果传入了姓名，则更新姓名
        if (accountInfoPutDTO.getAccName() != null) {
            oldAccountInfo.setAccName(accountInfoPutDTO.getAccName());
        }

        oldAccountInfo.setPassword(BCrypt.hashpw(accountInfoPutDTO.getPassword()));
        oldAccountInfo.setUpdateTime(new Date());
        boolean result = updateById(oldAccountInfo);

        if (!result) {
            throw new BusinessException("修改用户失败");
        }

        try {
            // 数据库更新成功后，再更新缓存
            if (accountInfoPutDTO.getAccPhone() != null && !accountInfoPutDTO.getAccPhone().equals(oldPhone)) {
                // 删除旧手机号缓存
                redisService.remove(RedisKeyConstant.ACCOUNT_PHONE_PREFIX + oldPhone);
                // 添加新手机号缓存
                redisService.setValue(RedisKeyConstant.ACCOUNT_PHONE_PREFIX + accountInfoPutDTO.getAccPhone(), 
                        accountInfoPutDTO.getAccount(),RedisKeyConstant.CACHE_TIME);
            }
            // 清除相关缓存
            clearCache();
            redisService.remove(RedisKeyConstant.ACCOUNT_INFO_PREFIX + oldAccountInfo.getId());
            
            return true;
        } catch (Exception e) {
            log.error("更新缓存失败", e);
            // 这里可以选择:
            // 1. 抛出异常,回滚事务
            throw new BusinessException("更新缓存失败");
            // 或者
            // 2. 记录日志,返回成功(数据库已更新成功)
            // return true;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addAccountInfo(AccountInfoAddDTO accountInfoAddDTO) {
        //手机号参数校验以及必须是数字
        if (accountInfoAddDTO.getAccPhone() == null || accountInfoAddDTO.getAccPhone().length() != 11 || !accountInfoAddDTO.getAccPhone().matches("\\d+")) {
            throw new BusinessException(ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        // 检查手机号是否已存在
        checkPhoneExists(accountInfoAddDTO.getAccPhone(), null);

        AccountInfo accountInfo = new AccountInfo();
        accountInfo.setAccName(accountInfoAddDTO.getAccName());
        accountInfo.setAccPhone(accountInfoAddDTO.getAccPhone());
        accountInfo.setStatus(1); // 默认启用
        accountInfo.setCreateTime(new Date());
        accountInfo.setUpdateTime(new Date());

        // 生成账号
        accountInfo.setAccount(generateAccount());

        // 设置默认密码（手机号后6位）
        String defaultPassword = accountInfoAddDTO.getAccPhone().substring(5);
        accountInfo.setPassword(BCrypt.hashpw(defaultPassword));

        boolean result = save(accountInfo);
        if (!result) {
            throw new BusinessException("新增用户失败");
        }

        try {
            // 数据库操作成功后，再更新缓存
            clearCache();
            redisService.setValue(RedisKeyConstant.ACCOUNT_PHONE_PREFIX + accountInfo.getAccPhone(), 
                    accountInfo.getAccount());
            return true;
        } catch (Exception e) {
            log.error("更新缓存失败", e);
            // 这里可以选择:
            // 1. 抛出异常,回滚事务
            throw new BusinessException("更新缓存失败");
            // 或者
            // 2. 记录日志,返回成功(数据库已更新成功)
            // return true;
        }
    }

    @Override
    public String generateAccount() {
        // 获取最大的账号序号
        LambdaQueryWrapper<AccountInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(AccountInfo::getAccount);
        wrapper.last("LIMIT 1");

        AccountInfo lastAccount = getOne(wrapper);

        int nextNumber;
        if (lastAccount == null || !lastAccount.getAccount().startsWith("YZ")) {
            nextNumber = 1;
        } else {
            String currentNumber = lastAccount.getAccount().substring(2);
            nextNumber = Integer.parseInt(currentNumber) + 1;
        }

        return String.format("YZ%04d", nextNumber);
    }

    private void checkPhoneExists(String phone, String excludeId) {
        // 先从缓存中查找
        String phoneKey = RedisKeyConstant.ACCOUNT_PHONE_PREFIX + phone;
        if (redisService.isExists(phoneKey)) {
            String existingId = redisService.getValue(phoneKey);
            if (!existingId.equals(excludeId)) {
                throw new BusinessException("手机号已存在");
            }
            return;
        }

        // 缓存中不存在，查询数据库
        LambdaQueryWrapper<AccountInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AccountInfo::getAccPhone, phone);
        if (excludeId != null) {
            wrapper.ne(AccountInfo::getId, excludeId);
        }

        if (count(wrapper) > 0) {
            throw new BusinessException("手机号已存在");
        }
    }

    @Override
    public AccountVO login(LoginDTO loginDto) {

        LambdaQueryWrapper<AccountInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AccountInfo::getAccount, loginDto.getAccount());
        AccountInfo accountInfo = getOne(wrapper);
        if (accountInfo == null) {
            throw new BusinessException("账号不存在");
        }
        if (!BCrypt.checkpw(loginDto.getPassword(), accountInfo.getPassword())) {
            throw new BusinessException("密码错误");
        }
        AccountVO accountVO = new AccountVO();
        SaLoginModel saLoginModel = new SaLoginModel();
        saLoginModel.setExtra("account", accountInfo.getAccount());
        saLoginModel.setExtra("phone", accountInfo.getAccPhone());
        saLoginModel.setExtra("name", accountInfo.getAccName());

        StpUtil.login(loginDto.getAccount(),saLoginModel);
        accountVO.setAccount(accountInfo.getAccount());
        accountVO.setAccName(accountInfo.getAccName());
        accountVO.setAccPhone(accountInfo.getAccPhone());
        accountVO.setToken(StpUtil.getTokenValue());
        accountVO.setStatus(accountInfo.getStatus());
        return accountVO;
    }

    @Override
    public Page<AccountInfoVO> getAccount(PageDTO pageDTO) {
        // 1. 参数校验
        if (pageDTO == null || pageDTO.getPageNumber() <= 0 || pageDTO.getPageSize() <= 0) {
            throw new BusinessException(ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        
        // 2. 生成包含分页参数的缓存key
        String cacheKey = String.format("%s:%d:%d", 
            RedisKeyConstant.ACCOUNT_LIST,
            pageDTO.getPageNumber(),
            pageDTO.getPageSize());
        
        // 3. 尝试从缓存获取
        if (redisService.isExists(cacheKey)) {
            return redisService.getValue(cacheKey);
        }
        
        // 4. 查询数据库
        Page<AccountInfo> page = new Page<>(pageDTO.getPageNumber(), pageDTO.getPageSize());
        IPage<AccountInfoVO> voPage = baseMapper.selectAccountVOPage(page);
        
        // 5. 处理空结果缓存
        if (voPage != null && voPage.getTotal() > 0) {
            redisService.setValue(cacheKey, voPage, RedisKeyConstant.CACHE_TIME);
        } else {
            redisService.setValue(cacheKey, voPage, RedisKeyConstant.EMPTY_CACHE_TIME);
        }
        
        return (Page<AccountInfoVO>) voPage;
    }

    @Override
    public Page<AccountInfoVO> getListByCondition(AccountQueryDTO query) {
        // 1. 参数校验
        if (query == null ||  query.getPageSize() == null || query.getPageNumber() == null) {
            throw new BusinessException(ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        
        // 2. 生成包含查询条件的缓存key
        String cacheKey = String.format("%s:%s:%d:%d", 
            RedisKeyConstant.ACCOUNT_LIST,
            query.hashCode(),
            query.getPageNumber(),
            query.getPageSize());
        
        // 3. 尝试从缓存获取
        if (redisService.isExists(cacheKey)) {
            return redisService.getValue(cacheKey);
        }
        // 4. 查询数据库
        Page<AccountInfo> page = new Page<>(query.getPageNumber(), query.getPageSize());
        IPage<AccountInfoVO> voPage = baseMapper.selectAccountVOPageByCondition(page, query);
        
        // 5. 处理空结果缓存
        if (voPage != null && voPage.getTotal() > 0) {
            redisService.setValue(cacheKey, voPage, RedisKeyConstant.CACHE_TIME);
        } else {
            redisService.setValue(cacheKey, voPage, RedisKeyConstant.EMPTY_CACHE_TIME);
        }
        
        return (Page<AccountInfoVO>) voPage;
    }

    @Transactional
    @Override
    public Boolean updateStatus(String account, Integer status) {
        if (account == null || status == null) {
            throw new BusinessException(ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        if (status != 1 && status != 0) {
            throw new BusinessException(ResponseCode.STATUS_INVALID.getInfo());
        }
        LambdaQueryWrapper<AccountInfo> wra = new LambdaQueryWrapper<>();
        wra.eq(AccountInfo::getAccount, account);
        AccountInfo accountInfo = baseMapper.selectOne(wra);
        if (accountInfo == null) {
            throw new BusinessException("用户不存在");
        }
        if (Objects.equals(accountInfo.getStatus(), status)){
            throw new BusinessException("状态值未改变");
        }
            accountInfo.setStatus(status);
            LambdaQueryWrapper<AccountInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AccountInfo::getAccount, account);
            boolean success = update(accountInfo, wrapper);
            if (success) {
                // 清除相关缓存
                clearCache();
                return true;
            }
        return false;
    }

    /**
     * 清除人员相关缓存
     */
    private void clearCache() {
        // 使用模式匹配删除所有人员列表缓存
        redisService.removePattern(RedisKeyConstant.ACCOUNT_LIST + ":*");
        redisService.removePattern(RedisKeyConstant.ACCOUNT_PHONE_PREFIX + ":*");
        redisService.removePattern(RedisKeyConstant.ACCOUNT_INFO_PREFIX + "*");
    }
}



